package org.ytor.core.sqlflow.dsl.eval;

import org.ytor.core.sqlflow.dsl.expr.node.ExprNode;
import org.ytor.core.sqlflow.dsl.expr.node.support.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * created by yangtong on 2025/8/6 21:35:59
 * <br/>
 * 表达式AST树计算器
 */
public class ExprEvaluator {

    public Object evaluate(ExprNode node, EvalContext context) {
        if (node instanceof LiteralNode) {
            return ((LiteralNode) node).value;
        }

        if (node instanceof VariableNode) {
            String name = ((VariableNode) node).name;
            return context.getVariable(name);
        }

        if (node instanceof BinaryOpNode) {
            return evalBinary((BinaryOpNode) node, context);
        }

        if (node instanceof FunctionCallNode) {
            return evalFunction((FunctionCallNode) node, context);
        }

        if (node instanceof TupleNode) {
            List<Object> values = new ArrayList<>();
            for (ExprNode item : ((TupleNode) node).elements) {
                values.add(evaluate(item, context));
            }
            return values;
        }

        throw new RuntimeException("Unknown AST node type: " + node.getClass().getName());
    }


    private Object evalBinary(BinaryOpNode node, EvalContext context) {
        String op = node.operator.toLowerCase();
        Object left = evaluate(node.left, context);

        // 如果是and
        if ("and".equals(op)) {
            // 只要左边的表达式为false，就直接返回false
            if (!toBoolean(left)) {
                return false;
            }
            // 如果左边的表达式为true，则以右边表达式的真值作为整体的真值
            return toBoolean(evaluate(node.right, context));
        }

        // 如果是or
        if ("or".equals(op)) {
            // 只要左边的表达式为true，就直接返回true
            if (toBoolean(left)) {
                return true;
            }
            // 如果左边的表达式为false，则以右边表达式的真值作为整体的真值
            return toBoolean(evaluate(node.right, context));
        }

        Object right = evaluate(node.right, context);

        return switch (op) {
            case "==", "is" -> equal(left, right);
            case "!=", "not is", "is not" -> !equal(left, right);
            case ">" -> compare(left, right) > 0;
            case ">=" -> compare(left, right) >= 0;
            case "<" -> compare(left, right) < 0;
            case "<=" -> compare(left, right) <= 0;
            // and 和 or已经在上面处理了
            //case "and" -> toBoolean(left) && toBoolean(right);
            //case "or" -> toBoolean(left) || toBoolean(right);
            case "like" -> like(left, right);
            case "not like" -> !like(left, right);
            case "in" -> in(left, right);
            case "not in" -> !in(left, right);
            case "between" -> between(left, right);
            case "not between" -> !between(left, right);
            default -> throw new RuntimeException("Unknown binary operator: " + op);
        };
    }

    private Object evalFunction(FunctionCallNode node, EvalContext context) {
        List<Object> args = new ArrayList<>();
        for (ExprNode argNode : node.arguments) {
            args.add(evaluate(argNode, context));
        }
        return context.callFunc(node, args);
    }

    private boolean toBoolean(Object val) {
        return switch (val) {
            case null -> false;
            case Boolean b -> b;
            case Number number -> number.doubleValue() != 0;
            case String s -> !s.isEmpty();
            default -> true;
        };
    }

    private boolean equal(Object left, Object right) {
        if (Objects.equals(right, "empty")) {
            if (left == null) {
                return true;
            } else if (left instanceof String strLeft) {
                return strLeft.isBlank();
            } else {
                throw new RuntimeException("empty 只能和字符串比较，现在比较对象：" + left.getClass().getName());
            }
        }
        return Objects.equals(left, right);
    }

    private int compare(Object a, Object b) {
        if (a instanceof Number && b instanceof Number) {
            return Double.compare(((Number) a).doubleValue(), ((Number) b).doubleValue());
        }
        if (a instanceof String && b instanceof String) {
            return ((String) a).compareTo((String) b);
        }
        throw new RuntimeException("Unsupported comparison: " + a + " vs " + b);
    }

    private boolean like(Object a, Object b) {
        if (a == null || b == null) return false;
        String aStr = a.toString();
        String bStr = b.toString();
        // 全模糊
        if (bStr.startsWith("%") && bStr.endsWith("%")) {
            return aStr.contains(bStr.substring(1, bStr.length() - 1));
        }
        // 左模糊
        else if (bStr.startsWith("%")) {
            return aStr.endsWith(bStr.substring(1));
        }
        // 右模糊
        else if (bStr.endsWith("%")) {
            return aStr.startsWith(bStr.substring(0,  bStr.length() - 1));
        }

        return false;
    }

    private boolean in(Object left, Object right) {
        if (!(right instanceof List)) {
            throw new RuntimeException("Right operand must be a tuple (List)");
        }
        for (Object elem : (List<?>) right) {
            if (equal(left, elem)) return true;
        }
        return false;
    }

    private boolean between(Object val, Object tuple) {
        if (!(tuple instanceof List) || ((List<?>) tuple).size() != 2) {
            throw new RuntimeException("between的右值必须是长度为2的元组");
        }
        Object min = ((List<?>) tuple).get(0);
        Object max = ((List<?>) tuple).get(1);
        return compare(val, min) >= 0 && compare(val, max) <= 0;
    }
}

